﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
//using Microsoft.VisualStudio.TestTools.UnitTesting;
using Formsy.Data.Services;
using Formsy.Data.Linq;
using NUnit.Framework;
using Formsy.Data.Interfaces;
using Anthony.Library;
using System.Data.SqlTypes;

namespace Formsy.Test
{
    [TestFixture]
    public class FormsyServiceTest
    {
        string m_FormName = "UnitTest";

        Dictionary<string, string> m_Dictionary;

        Dictionary<string, string> m_DictionaryUpdate;

        int m_EntryId = 27;

        DateTime m_MinDate;
        DateTime m_MaxDate;


        public FormsyServiceTest()
        {
        }



        // TESTS
        // csv methods
        //DataTable GetCSV(string competitionName, DateTime start, DateTime end, string path, List<string> ignoreList);
        //DataTable GetHeadings(List<IFormsyEntry> entries, List<string> nonDataHeadings, DataTable table, List<string> ignoreList);


        #region Setup and TearDown

        [TestFixtureSetUp]
        public void Setup()
        {
            m_Dictionary = new Dictionary<string, string>();
            m_Dictionary.Add("First Name", "Anthony");
            m_Dictionary.Add("Last Name", "Dang");
            m_Dictionary.Add("Email", "formsy_recipient@yourdomain.com");

            m_DictionaryUpdate = new Dictionary<string, string>();
            m_DictionaryUpdate.Add("First Name", "Avril");
            m_DictionaryUpdate.Add("Last Name", "Lavigne");
            m_DictionaryUpdate.Add("Email", "noemail@noemail.com");

            m_MinDate = DateTime.Parse(SqlDateTime.MinValue.ToString());
            m_MaxDate = DateTime.Parse(SqlDateTime.MaxValue.ToString());

        }

        [TestFixtureTearDown]
        public void TearDown()
        {
        }

        #endregion


        #region InsertEntry

        // IFormsyEntry InsertEntry(string formName);
        private void InsertEntry()
        {
            IFormsyEntry entry = HttpDataService.Instance.FormsyService.InsertEntry(m_FormName);
            Assert.IsNotNull(entry);

            IFormsyForm form = HttpDataService.Instance.FormsyService.GetForm(m_FormName);
            Assert.IsNotNull(form);

            m_EntryId = entry.Id;
        }

        #endregion



        #region InsertEntryData

        // List<IFormsyEntryData> InsertEntryData(int entryId, Dictionary<string, string> dictionary);
        // protected void AddXmlToEntry(int entryId, List<FormsyEntryData> dataItems)
        // IFormsyEntry GetEntry(int entryId);
        // public List<IFormsyEntryData> GetEntryDatas(int entryId)
        [Test]
        public void InsertEntryData()
        {
            // create an entry first!
            InsertEntry();

            // get formId
            int formId = GetFormId();

            // insert
            var datasInserted = HttpDataService.Instance.FormsyService.InsertEntryData(formId, m_EntryId, m_Dictionary);
            Assert.IsNotEmpty(datasInserted);

            // get data out 
            // tests GetEntryDatas(int entryId)
            var datasRetrieved = HttpDataService.Instance.FormsyService.GetEntryDatas(m_EntryId);
            Assert.IsNotEmpty(datasRetrieved);

            // compare
            Assert.AreEqual(datasInserted.Count, datasRetrieved.Count);

            for (int i = 0; i < datasInserted.Count; i++)
            {
                Assert.AreEqual(datasInserted[i].Id, datasRetrieved[i].Id);
                Assert.AreEqual(datasInserted[i].EntryId, datasRetrieved[i].EntryId);
                Assert.AreEqual(datasInserted[i].Name, datasRetrieved[i].Name);
                Assert.AreEqual(datasInserted[i].Value, datasRetrieved[i].Value);
            }

            // get xml from entry, ensure that it was serialized and saved.
            // get xml from entry - tests GetEntry()
            IFormsyEntry entry = HttpDataService.Instance.FormsyService.GetEntry(m_EntryId);
            Assert.IsNotNull(entry);

            List<FormsyEntryData> list = datasInserted.Cast<FormsyEntryData>().ToList();
            string xml = XmlSerializing.ToXml(list, typeof(List<FormsyEntryData>));

            // tests saved xml
            Assert.AreEqual(entry.Xml, xml);

            // test deserialization.
            List<FormsyEntryData> deserializedDatas = (List<FormsyEntryData>)XmlSerializing.FromXml(entry.Xml, typeof(List<FormsyEntryData>));
            for (int i = 0; i < deserializedDatas.Count; i++)
            {
                Assert.AreEqual(datasInserted[i].Id, deserializedDatas[i].Id);
                Assert.AreEqual(datasInserted[i].EntryId, deserializedDatas[i].EntryId);
                Assert.AreEqual(datasInserted[i].Name, deserializedDatas[i].Name);
                Assert.AreEqual(datasInserted[i].Value, deserializedDatas[i].Value);
            }

        }


        #endregion



        #region UpdateEntryData

        // List<IFormsyEntryData> UpdateEntryData(int entryId, Dictionary<string, string> dictionary);
        [Test]
        public void UpdateEntryData()
        {
            InsertEntryData();

            // get data out 
            var datasRetrieved = HttpDataService.Instance.FormsyService.GetEntryDatas(m_EntryId);
            Assert.IsNotEmpty(datasRetrieved);

            List<IFormsyEntryData> cloned = new List<IFormsyEntryData>();

            // make a copy of the items because the items in datasRetrieved are pointing to the data context.
            foreach (var v in datasRetrieved)
            {
                FormsyEntryData d = new FormsyEntryData();
                d.EntryId = v.EntryId;
                d.Id = v.Id;
                d.Name = v.Name;
                d.Value = v.Value;
                cloned.Add(d);
            }


            // get formId
            int formId = GetFormId();

            // update
            var datasUpdated = HttpDataService.Instance.FormsyService.UpdateEntryData(formId, m_EntryId, m_DictionaryUpdate);
            Assert.IsNotEmpty(datasUpdated);

            // compare sizes
            Assert.AreEqual(datasRetrieved.Count, datasUpdated.Count);

            // compare values
            for (int i = 0; i < datasUpdated.Count; i++)
            {
                Assert.AreEqual(datasUpdated[i].Id, cloned[i].Id);
                Assert.AreEqual(datasUpdated[i].EntryId, cloned[i].EntryId);
                Assert.AreEqual(datasUpdated[i].Name, cloned[i].Name);
                Assert.AreNotEqual(datasUpdated[i].Value, cloned[i].Value); // the values were changed
            }

            // test that the xml was serialized and saved in the entry
            // get xml from entry - tests GetEntry()
            IFormsyEntry entry = HttpDataService.Instance.FormsyService.GetEntry(m_EntryId);
            Assert.IsNotNull(entry);

            // test saved xml
            string xml = XmlSerializing.ToXml(datasUpdated.Cast<FormsyEntryData>().ToList(), typeof(List<FormsyEntryData>));
            Assert.AreEqual(entry.Xml, xml);

            // test deserialization.
            List<FormsyEntryData> deserializedDatas = (List<FormsyEntryData>)XmlSerializing.FromXml(entry.Xml, typeof(List<FormsyEntryData>));

            CompareLists(datasUpdated.Cast<FormsyEntryData>().ToList(), deserializedDatas);
        }

        #endregion



        #region GetForm

        // IFormsyForm GetForm(string formName);
        [Test]
        public void GetForm()
        {
            var form = HttpDataService.Instance.FormsyService.GetForm(m_FormName);
            Assert.IsNotNull(form);
            Assert.AreEqual(form.Name, m_FormName);
        }

        #endregion



        #region EnsureFormExists

        // void EnsureFormExists(string formName);
        // IFormsyForm CreateForm(string formName);
        [Test]
        public void EnsureFormExists()
        {
            // make a form name with suffix
            int i = 0;
            string formName = m_FormName + i;
            while (true)
            {
                IFormsyForm test = HttpDataService.Instance.FormsyService.GetForm(formName);
                if (test == null)
                    break;
                formName = m_FormName + i++;
            }

            // create a form
            IFormsyForm createdForm = HttpDataService.Instance.FormsyService.CreateForm(formName);
            Assert.IsNotNull(createdForm);

            // get the form (ensure it exists)
            IFormsyForm form = HttpDataService.Instance.FormsyService.EnsureFormExists(formName);
            Assert.IsNotNull(form);

            // ensure it's the same form
            Assert.AreEqual(createdForm.Id, form.Id);
            Assert.AreEqual(createdForm.Name, form.Name);
        }

        #endregion



        #region GetEntries

        //List<IFormsyEntry> GetEntries(string formName, DateTime start, DateTime end);
        [Test]
        public void GetEntries()
        {
            List<IFormsyEntry> entries = HttpDataService.Instance.FormsyService.GetEntries(m_FormName, m_MinDate, m_MaxDate);
            Assert.IsNotNull(entries);
            Assert.IsNotEmpty(entries);
        }

        #endregion



        #region GetEntryDatas

        //public List<IFormsyEntryData> GetEntryDatas(int entryId)
        [Test]
        public void GetEntryDatas()
        {
            List<IFormsyEntryData> datas = HttpDataService.Instance.FormsyService.GetEntryDatas(m_EntryId);
            Assert.IsNotNull(datas);
            Assert.IsNotEmpty(datas);
        }

        #endregion




        #region TestEntryToDataXmlConsistency

        [Test]
        public void TestEntryToDataXmlConsistency()
        {
            // get entries
            List<IFormsyEntry> entries = HttpDataService.Instance.FormsyService.GetEntries(m_FormName, m_MinDate, m_MaxDate);
            Assert.IsNotNull(entries);
            Assert.IsNotEmpty(entries);

            foreach (var entry in entries)
            {
                // get datas for this entry
                List<IFormsyEntryData> datas = HttpDataService.Instance.FormsyService.GetEntryDatas(entry.Id);
                Assert.IsNotNull(datas);
                Assert.IsNotEmpty(datas);

                // serialize the datas to xml
                string xml = XmlSerializing.ToXml(datas.Cast<FormsyEntryData>().ToList(), typeof(List<FormsyEntryData>));

                // check xml against entry.Xml
                Assert.AreEqual(xml, entry.Xml);

                // double-check by deserializing entry.Xml, and checking against datas list
                List<FormsyEntryData> datasFromEntry = (List<FormsyEntryData>)XmlSerializing.FromXml(entry.Xml, typeof(List<FormsyEntryData>));

                CompareLists(datas.Cast<FormsyEntryData>().ToList(), datasFromEntry);
            }

        }

        #endregion




        #region GetEntryDatas

        //public List<IFormsyEntryData> GetEntryDatas(int entryId)
        [Test]
        public void XmlTest()
        {
            var data = HttpDataService.Instance.FormsyService.GetEntryDatas(m_EntryId);

            List<FormsyEntryData> cased = data.Cast<FormsyEntryData>().ToList();
            string xml = XmlSerializing.ToXml(cased, cased.GetType());

            var v = XmlSerializing.FromXml(xml, cased.GetType());


        }

        #endregion

        protected void CompareLists(List<FormsyEntryData> list1, List<FormsyEntryData> list2)
        {
            // compare sizes
            Assert.AreEqual(list1.Count, list2.Count);

            // compare values
            for (int i = 0; i < list1.Count; i++)
            {
                Assert.AreEqual(list1[i].Id, list2[i].Id);
                Assert.AreEqual(list1[i].EntryId, list2[i].EntryId);
                Assert.AreEqual(list1[i].Name, list2[i].Name);
                Assert.AreEqual(list1[i].Value, list2[i].Value); // the values were changed
            }
        }



        private int GetFormId()
        {
            var db = new FormsyDataContext();
            int formId = (from entry in db.FormsyEntries
                          where entry.Id == m_EntryId
                          select entry.FormId).Single();
            return formId;
        }

    }

}
